<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>js中的this指向</title>
</head>
<body>
<script>

    a = 10;
    console.log(a);
    console.log(window.a);
    console.log(this.a);

    //this  ==> context 上下文
    {//1.方法是谁调用的,那么在方法中this就指向谁(.前面是谁, this就是谁)
        let obj = {
            name: "obj",
            fn: function () {
                console.log(this);//obj
            }
        };
        obj.fn();
    }
    {//2.如果没有调用 this始终指向window
        function fn() {
            console.log(this);//window
        }
        fn();
    }
    {//3.构造函数中的this, 指向实例本身
        function Fn(name){
            this.name = name;
            this.age = 18;
            console.log("Fn中的this==>",this); //new Fn()
        }
        Fn.prototype.sayName = function(){
            console.log(this.name); //new Fn()
            console.log("sayName中的this==>",this)
        }

        let fn = new Fn("哈哈");
        fn.sayName()
        console.log(fn);
    }
    {//4.强制改变this   call apply bind
        //call和apply和bind都是改变this指向的方法
        //语法
        //call(新的this指向, pram1, pram2 ...)
        //apply(新的this指向, [pram1, pram2 ...])
        //bind方法 返回一个改变this指向之后的新的方法,需要手动调用
        let obj = {
            name: "obj",
            birth: 1990,
            year: 2021,
            age: function(arg1, arg2){
                console.log(this);//obj2
                console.log(arg1, arg2);//obj2
                console.log("my age =", this.year - this.birth)
            }
        }
        // obj.age("参数1","参数2");

        let obj2 = {
            name: "obj2",
            birth: 2000,
            year: 2020,
        };
        // obj.age.call(obj2,"参数1","参数2")
        // obj.age.apply(obj2,["参数1","参数2"])// Create List From Array Like called on non-object
        //bind
        let changeThisAge = obj.age.bind(obj2);
        changeThisAge("参数1","参数2")
    }

    //1.方法是谁调用的,那么在方法中this就指向谁(.前面是谁, this就是谁)
    //2.如果没有调用 this始终指向window
    //3.构造函数中的this, 指向实例本身
    //4.强制改变this   call apply bind

    {//ES5中的this解决方案 一般使用闭包将父级的this指向进行暂存,然后在子集作用域中去使用这边暂存的变量,来去确定this 指向
        let obj = {
            name: "obj",
            fn: function () {
                console.log(this);//obj
                let that = this;
                function fn2(){//闭包
                    console.log("fn2 中的this指向=========>",this, that);//window  希望==> obj
                }
                fn2()
            }
        };
        obj.fn();
    }
    {//箭头函数
        let obj = {
            name: "obj",
            fn: function () {
                console.log(this);//obj
                let fn2 = ()=>{//闭包
                    console.log("箭头函数 fn2 中的this指向=========>",this);//obj
                }
                fn2()
            }
        };
        obj.fn();
    }


    //箭头函数的出现就是为了解决ES5中this指向混乱的问题
    //箭头函数的this指向来自父级上下文, 箭头函数没有自己的this
    //箭头函数的this不会在调用的时候被改变, 在箭头函数声明的时候他的this就已经被永久的确定










    // 补充
    {//for in 和for of 区别
        let arr = ["a","b","c","d","e","f"];
        //使用for in遍历数组的时候 key的值是下标
        for(let key in arr){
            console.log(key)
        }
        //使用for of遍历数组的时候 key是数组中的每一项
        for(let value of arr){//arr is iterable  数组有一个 Symbol(Symbol.iterator)
            console.log(value)
        }

        console.log(arr)

        let obj = {
            a: 1,
            b: 2,
            c: 3,
            d: 4,
        }
        //使用for in遍历对象的时候 key的值是属性名
        for(let key in obj){
            console.log(key)
        }
        //使用for in遍历对象的时候 key的值是属性名
        // for(let key of obj){//报错 obj is not iterable
        //     console.log(key)
        // }
    }


</script>
</body>
</html>